package cn.hutool.postfix.generator.common;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;

import java.text.NumberFormat;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 方法顺序执行时 简化 stop操作
 * 不支持 多线程 并发 watch ,单线程 出异常需要清除; 否则下次打印日志可能有错误重复的日志;
 * 内存溢出的情况(同一线程短时间一直在执行错误的代码,没有机会 remove)
 *
 * @author liuxiongkang
 */
public class Watch {

    private static final int WATCH_TIME_OUT_MINUTES = 10;
    private static final ThreadLocal<Watch> WATCH_THREAD_LOCAL = ThreadLocal.withInitial(Watch::new);
    private final AppStopWatch stopWatch = new AppStopWatch();
    private final LocalDateTime start = LocalDateTime.now();

    public static void start(String taskName) {
        Watch watch = WATCH_THREAD_LOCAL.get();
        if (Duration.between(watch.start, LocalDateTime.now()).toMinutes() >= WATCH_TIME_OUT_MINUTES) {
            watch = new Watch();
            WATCH_THREAD_LOCAL.set(watch);
        }
        AppStopWatch stopWatch = watch.stopWatch;
        if (stopWatch.isRunning()) {
            stopWatch.stop();
        }
        stopWatch.start(taskName);
    }

    /**
     * 只能使用一次, 一个线程使用多次 数据会有问题,
     */
    public static String prettyPrint(String id) {
        AppStopWatch stopWatch = WATCH_THREAD_LOCAL.get().stopWatch;
        if (stopWatch.isRunning()) {
            stopWatch.stop();
        }
        stopWatch.setId(id);
        String prettyPrint = stopWatch.prettyPrint();
        WATCH_THREAD_LOCAL.remove();
        return prettyPrint;
    }

    static class AppStopWatch extends StopWatch {
        String id;

        public void setId(String id) {
            this.id = id;
        }

        @Override
        public String prettyPrint() {
            StringBuilder sb = new StringBuilder(CharSequenceUtil.format("{} 耗时 {} ms", id, getTotalTimeNanos() / 1000000));
            sb.append(FileUtil.getLineSeparator());
            if (null == getTaskInfo()) {
                sb.append("未找到任务信息!");
            } else {
                final NumberFormat nf = NumberFormat.getNumberInstance();
                nf.setMinimumIntegerDigits(9);
                nf.setGroupingUsed(false);
                final NumberFormat pf = NumberFormat.getPercentInstance();
                pf.setMinimumIntegerDigits(3);
                pf.setGroupingUsed(false);
                int i = 1;
                for (TaskInfo task : getTaskInfo()) {
                    sb.append(nf.format(task.getTimeNanos() / 1000000)).append(" ms  ");
                    sb.append(pf.format((double) task.getTimeNanos() / getTotalTimeNanos())).append("  ");
                    sb.append("task").append(i++).append(": ");
                    sb.append(task.getTaskName()).append(FileUtil.getLineSeparator());
                }
            }
            return sb.toString();
        }
    }
}
